﻿using System;
using System.Linq.Expressions;
using NPOI.SS.Formula.Functions;
using OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
using OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
using Simple.Repository.Models;
using Simple.Services.System;
using Simple.Services.System.Recipes.Models;


namespace Simple.Services;

public class RecipesService : BusinessBaseService
{
    private readonly SimpleDbContext _context;

    public RecipesService(SimpleDbContext context, ISimpleService services) : base(services)
    {
        _context = context;
    }


    public async Task<PageResultModel<RecipesModel>> GetPageAsync(RecipesPageInputModel input)
    {
        var result = new PageResultModel<RecipesModel>();
        var query = _context.Set<Recipes>().Include(x => x.RecipesDetailsList).AsQueryable();

        // 根据条件查询 
        if (!string.IsNullOrEmpty(input.RecipeName))
        {
            query = query.Where(p => EF.Functions.Like(p.RecipeName, $"%{input.RecipeName}%"));
        }

        // 获取总数量
        result.TotalRows = await query.CountAsync();

        // 分页查询
        query = query.OrderByDescending(x => x.CreatedTime).Page(input.PageNo, input.PageSize);
        var positions = await query.ToListAsync();

        var data = MapperHelper.Map<List<RecipesModel>>(positions);

        result.Rows = data;

        result.SetPage(input);
        result.CountTotalPage();

        return result;

    }

    public async Task<List<RecipesFoodViewModel>> GetRecipesDatailAsync(Guid recipesId)
    {
        var query = _context.Set<RecipesDetails>().AsQueryable();
        query = query.Where(x => x.RecipesId == recipesId).Include(p => p.FoodMaterials);
        var positions = await query.ToListAsync();
        var result = new List<RecipesFoodViewModel>();
        foreach (var item in positions)
        {
            var data = new RecipesFoodViewModel();
            data.Id = item.Id;
            data.RecipesId = item.RecipesId;
            data.Weight = item.Weight;
            data.FoodMaterials = MapperHelper.Map<FoodMaterialsViewModel>(item.FoodMaterials);
            result.Add(data);
        }

        return result;

    }

    public async Task<int> AddAsync(RecipesModel model)
    {
        if (await _context.Set<Recipes>().AnyAsync(p => p.Id != model.Id && p.RecipeName == model.RecipeName))
        {
            throw AppResultException.Status409Conflict("存在相同名称的食谱");
        }

        var position = MapperHelper.Map<Recipes>(model);
        await _context.AddAsync(position);
        return await _context.SaveChangesAsync();
    }

    public async Task<Guid> UpdateAsync(RecipesModel model)
    {
        if (await _context.Set<Recipes>().AnyAsync(p => p.Id != model.Id && p.RecipeName == model.RecipeName))
        {
            throw AppResultException.Status409Conflict("存在相同名称的食谱");
        }

        var query = _context.Set<Recipes>().Include(x => x.RecipesDetailsList).AsQueryable();

        var recipes = await query.Where(p => model.Id == p.Id).FirstOrDefaultAsync();
        if (recipes == null)
        {
            throw AppResultException.Status404NotFound("找不到食谱，更新失败");
        }

        recipes.RecipeName = model.RecipeName;
        recipes.Abbreviation = model.Abbreviation;
        recipes.RecipesDetailsList = MapperHelper.Map<List<RecipesDetails>>(model.RecipesDetailsList);
        _context.Update(recipes);


        int ret = await _context.SaveChangesAsync();
        if (ret == 0)
        {
            throw AppResultException.Status200OK("更新记录数为0");
        }

        return model.Id;
    }

    public async Task<int> DeleteAsync(IEnumerable<Guid> ids)
    {
        var positions = await _context.Set<Recipes>()
            .Where(p => ids.Contains(p.Id))
            .ToListAsync();
        _context.RemoveRange(positions);
        return await _context.SaveChangesAsync();
    }

    public async Task<PlanDayRecipesModel> GetPlanDayRecipesAsync(PlanRecipesInputModel model)
    {
        var query = _context.Set<PlanDayRecipes>().AsQueryable().Include(x => x.PlanDayRecipesDetails).ThenInclude(p => p.Recipes).ThenInclude(a => a.RecipesDetailsList).ThenInclude(z => z.FoodMaterials).AsQueryable();
        query = query.Where(p => p.Date == model.Day);
        var positions = await query.FirstOrDefaultAsync();
        var result = new PlanDayRecipesModel();



        if (positions != null)
        {
            result.Id = positions.Id;
            result.PlanWeekRecipesId = positions.PlanWeekRecipesId;
            result.Date = positions.Date;
            result.DateStr = positions.DateStr;
            result.Number = positions.Number;
            result.PlanDayRecipesDetails = new List<PlanDayRecipesDetailModel>();


            foreach (EnumRecipes day in Enum.GetValues(typeof(EnumRecipes)))
            {
                var temp = new PlanDayRecipesDetailModel();
                var dayList = positions.PlanDayRecipesDetails.Where(x => x.Type == day).ToList();

                temp.Type = day;
                temp.Recipes = MapperHelper.Map<List<RecipesModel>>(dayList.Select(x => x.Recipes).ToList());

                foreach (var item in temp.Recipes)
                {
                    foreach (var recipesDetail in item.RecipesDetailsList)
                    {
                        recipesDetail.QuantityRequired = (recipesDetail.Weight * positions.Number) / 500;
                    }
                }
                result.PlanDayRecipesDetails.Add(temp);
            }



            var nutritionalAnalysisData = await _context.Set<NutritionalAnalysis>().Where(x => x.Date == model.Day).FirstOrDefaultAsync();
            if (nutritionalAnalysisData != null)
            {
                result.NutritionalAnalysisDto = new NutritionalAnalysisDto()
                {
                    Heat = nutritionalAnalysisData.Heat,
                    Protein = nutritionalAnalysisData.Protein,
                    Carbohydrate = nutritionalAnalysisData.Carbohydrate,
                    Fat = nutritionalAnalysisData.Fat,
                };
            }
        }
        return result;
    }

    public async Task<int> SavePlanWeek(AddPlanRecipesDto dto)
    {

        if (_context.Set<PlanWeekRecipes>().Any(p => p.Id == dto.Id))
        {
            var d = _context.Set<PlanWeekRecipes>().Where(p => p.Id == dto.Id).First();
            _context.Remove(d);
            await _context.SaveChangesAsync();
        }

        var nutritionalAnalysisList = new List<NutritionalAnalysis>();

        var week = new PlanWeekRecipes();
        week.Id = Guid.NewGuid();
        week.PlanName = dto.PlanName;
        week.PlanRange = dto.PlanRange;
        week.StarTime = dto.StarTime;
        week.EndTime = dto.EndTime;

        week.PlanRecipesList = new List<PlanDayRecipes>();
        foreach (var planday in dto.PlanDayRecipesList)
        {
            var day = new PlanDayRecipes();
            day.Id = Guid.NewGuid();
            day.PlanWeekRecipesId = week.Id;
            day.Date = planday.Date;
            day.DateStr = planday.DateStr;
            day.Number = planday.Number;

            var dayNutritionalAnalysis = new NutritionalAnalysis();
            dayNutritionalAnalysis.Id = Guid.NewGuid();
            dayNutritionalAnalysis.PlanWeekRecipesId = week.Id;
            dayNutritionalAnalysis.Date = planday.Date;
            dayNutritionalAnalysis.DateStr = planday.DateStr;
            dayNutritionalAnalysis.Heat = planday.NutritionalAnalysisDto.Heat;
            dayNutritionalAnalysis.Protein = planday.NutritionalAnalysisDto.Protein;
            dayNutritionalAnalysis.Fat = planday.NutritionalAnalysisDto.Fat;
            dayNutritionalAnalysis.Carbohydrate = planday.NutritionalAnalysisDto.Carbohydrate;
            dayNutritionalAnalysis.Calcium = planday.NutritionalAnalysisDto.Calcium;
            dayNutritionalAnalysis.Iron = planday.NutritionalAnalysisDto.Iron;
            dayNutritionalAnalysis.Zinc = planday.NutritionalAnalysisDto.Zinc;
            dayNutritionalAnalysis.VitA = planday.NutritionalAnalysisDto.VitA;
            dayNutritionalAnalysis.VitB1 = planday.NutritionalAnalysisDto.VitB1;
            dayNutritionalAnalysis.VitB2 = planday.NutritionalAnalysisDto.VitB2;
            dayNutritionalAnalysis.VitC = planday.NutritionalAnalysisDto.VitC;
            nutritionalAnalysisList.Add(dayNutritionalAnalysis);

            day.PlanDayRecipesDetails = new List<PlanDayRecipesDetail>();
            foreach (var planDayDateil in planday.PlanDayRecipesDetails)
            {

                foreach (var recipesId in planDayDateil.RecipesIdList)
                {
                    var dayDateil = new PlanDayRecipesDetail();
                    dayDateil.Id = Guid.NewGuid();
                    dayDateil.PlanDayRecipesId = day.Id;
                    dayDateil.Type = planDayDateil.Type;
                    dayDateil.RecipesId = recipesId;
                    day.PlanDayRecipesDetails.Add(dayDateil);
                }
            }
            week.PlanRecipesList.Add(day);
        }
        await _context.AddAsync(week);

        await _context.AddRangeAsync(nutritionalAnalysisList);
        int ret = await _context.SaveChangesAsync();
        return ret;
    }

    public async Task<int> DeletePlanAsync(Guid planweekrecipesId)
    {
        _context.RemoveRange(_context.Set<PlanWeekRecipes>().Where(p => p.Id == planweekrecipesId));
        int ret = await _context.SaveChangesAsync();
        return ret;
    }

    public async Task<PageResultModel<PlanWeekRecipesModel>> GetPlanWeekAsync(PlanWeekQueryModel input)
    {
        var result = new PageResultModel<PlanWeekRecipesModel>();
        var query = await OrganizationFilter(_context.Set<PlanWeekRecipes>().AsQueryable());

        // 根据条件查询 
        if (!string.IsNullOrEmpty(input.PlanName))
        {
            query = query.Where(p => EF.Functions.Like(p.PlanName, $"%{input.PlanName}%"));
        }
        if (input.StartDate.HasValue && input.EndDate.HasValue)
        {
            query = query.Where(p => input.StartDate > p.StarTime && input.EndDate.Value < p.EndTime.AddDays(1));
        }

        // 获取总数量
        result.TotalRows = await query.CountAsync();

        // 分页查询
        query = query.OrderBy(x => x.CreatedTime).Page(input.PageNo, input.PageSize);
        var positions = await query.ToListAsync();
        result.Rows = MapperHelper.Map<List<PlanWeekRecipesModel>>(positions);

        result.SetPage(input);
        result.CountTotalPage();

        return result;

    }


    public async Task<List<PlanDayRecipesViewModel>> GetPlanWeekDetailAsync(Guid planWeekRecipesId)
    {
        var query = _context.Set<PlanDayRecipes>().AsQueryable().Include(x => x.PlanDayRecipesDetails).ThenInclude(p => p.Recipes).ThenInclude(a => a.RecipesDetailsList).ThenInclude(z => z.FoodMaterials).AsQueryable();
        query = query.Where(p => p.PlanWeekRecipesId == planWeekRecipesId);
        var positions = await query.ToListAsync();

        var result = new List<PlanDayRecipesViewModel>();
        var nutritionalAnalysisQuery = _context.Set<NutritionalAnalysis>().AsQueryable();

        foreach (var item in positions)
        {
            var planDayRecipesViewModel = new PlanDayRecipesViewModel();
            planDayRecipesViewModel.PlanWeekRecipesId = planWeekRecipesId;
            planDayRecipesViewModel.Date = item.Date;
            planDayRecipesViewModel.DateStr = item.DateStr;
            planDayRecipesViewModel.Number = item.Number;
            planDayRecipesViewModel.PlanDayRecipesDetails = new List<PlanDayRecipesDetailViewModel>();

            foreach (EnumRecipes type in Enum.GetValues(typeof(EnumRecipes)))
            {
                var planDayRecipesDetailViewModel = new PlanDayRecipesDetailViewModel();
                planDayRecipesDetailViewModel.Type = type;
                planDayRecipesDetailViewModel.RecipesList = new List<RecipesViewModel>();
                foreach (var recipes in item.PlanDayRecipesDetails.Where(x => x.Type == type).ToList())
                {
                    var recipesViewModel = new RecipesViewModel();
                    recipesViewModel.RecipesId = recipes.Recipes.Id;
                    recipesViewModel.RecipesName = recipes.Recipes.RecipeName;
                    recipesViewModel.RecipesDetailsList = new List<RecipesDetailsViewModel>();
                    foreach (var recipesDetails in recipes.Recipes.RecipesDetailsList)
                    {
                        var recipesDetailsViewModel = new RecipesDetailsViewModel();
                        recipesDetailsViewModel.FoodName = recipesDetails.FoodMaterials.FoodName;
                        recipesDetailsViewModel.Weight = recipesDetails.Weight;
                        recipesViewModel.RecipesDetailsList.Add(recipesDetailsViewModel);
                    }
                    planDayRecipesDetailViewModel.RecipesList.Add(recipesViewModel);
                }
                planDayRecipesViewModel.PlanDayRecipesDetails.Add(planDayRecipesDetailViewModel);
            }


            var nutritionalAnalysisData = await nutritionalAnalysisQuery.Where(x => x.Date == item.Date).FirstOrDefaultAsync();
            if (nutritionalAnalysisData != null)
            {
                planDayRecipesViewModel.NutritionalAnalysisDto = new NutritionalAnalysisDto()
                {
                    Heat = nutritionalAnalysisData.Heat,
                    Protein = nutritionalAnalysisData.Protein,
                    Carbohydrate = nutritionalAnalysisData.Carbohydrate,
                    Fat = nutritionalAnalysisData.Fat,
                    Calcium = nutritionalAnalysisData.Calcium,
                    Iron = nutritionalAnalysisData.Iron,
                    VitA = nutritionalAnalysisData.VitA,
                    VitB1 = nutritionalAnalysisData.VitB1,
                    VitB2 = nutritionalAnalysisData.VitB2,
                    VitC = nutritionalAnalysisData.VitC,
                    Zinc = nutritionalAnalysisData.Zinc,
                };
            }
            result.Add(planDayRecipesViewModel);
        }
        return result;
    }

    public async Task<WeekQuantityRequiredViewModel> GetWeekPurchaseAsync(Guid PlanWeekRecipesId)
    {
        var result = new WeekQuantityRequiredViewModel();

        var weekData = await _context.Set<PlanWeekRecipes>().Where(x => x.Id == PlanWeekRecipesId).FirstAsync();

        var data = await GetPlanWeekDetailAsync(PlanWeekRecipesId);

        result.PlanRange = weekData.PlanRange;
        result.FoodLists = new List<FoodList>();

        foreach (var item in data)
        {

            foreach (var day in item.PlanDayRecipesDetails)
            {
                foreach (var recipes in day.RecipesList)
                {
                    foreach (var recipesDetail in recipes.RecipesDetailsList)
                    {
                        var food = new FoodList();
                        food.DayQuantityRequiredList = new List<DayQuantityRequiredViewModel>();
                        if (result.FoodLists.Any(x => x.FoodName == recipesDetail.FoodName))
                        {
                            foreach (var foods in result.FoodLists)
                            {
                                if (foods.FoodName == recipesDetail.FoodName)
                                {
                                    if (foods.DayQuantityRequiredList.Any(x => x.Date == item.Date))
                                    {
                                        foods.DayQuantityRequiredList.First(x => x.Date == item.Date).QuantityRequired = foods.DayQuantityRequiredList.First(x => x.Date == item.Date).QuantityRequired + ((recipesDetail.Weight * item.Number) / 500);
                                    }
                                    else
                                    {
                                        foods.DayQuantityRequiredList.Add(new DayQuantityRequiredViewModel()
                                        {
                                            Date = item.Date,
                                            DateStr = item.DateStr,
                                            Number = item.Number,
                                            QuantityRequired = (recipesDetail.Weight * item.Number) / 500
                                        });
                                    }



                                }

                            }
                        }
                        else
                        {
                            food.FoodName = recipesDetail.FoodName;
                            food.DayQuantityRequiredList.Add(new DayQuantityRequiredViewModel()
                            {
                                Date = item.Date,
                                DateStr = item.DateStr,
                                Number = item.Number,
                                QuantityRequired = (recipesDetail.Weight * item.Number) / 500
                            });
                            result.FoodLists.Add(food);
                        }

                    }

                }
            }
        }
        return result;
    }



    public async Task<WeekQuantityRequiredViewModelV2> GetWeekPurchaseAsyncV2(Guid PlanWeekRecipesId)
    {
        var result = new WeekQuantityRequiredViewModelV2();

        var weekData = await GetWeekPurchaseAsync(PlanWeekRecipesId);

        result.PlanRange = weekData.PlanRange;
        result.FoodLists = new List<FoodListV2>();

        var dateList = new List<string> { "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期天" };
        foreach (var item in weekData.FoodLists)
        {
            var food = new FoodListV2();
            food.FoodName = item.FoodName;
            food.TotalQuantity = item.DayQuantityRequiredList.Sum(x=>x.QuantityRequired);
            foreach (var date in dateList)
            {
                var dateData = item.DayQuantityRequiredList.FirstOrDefault(x => x.DateStr == date);
                if (dateData != null)
                {
                    switch (date)
                    {
                        case "星期一":
                            food.Monday = dateData.QuantityRequired;
                            break;
                        case "星期二":
                            food.Tuesday = dateData.QuantityRequired;
                            break;
                        case "星期三":
                            food.Wednesday = dateData.QuantityRequired;
                            break;
                        case "星期四":
                            food.Thursday = dateData.QuantityRequired;
                            break;
                        case "星期五":
                            food.Friday = dateData.QuantityRequired;
                            break;
                        case "星期六":
                            food.Saturday = dateData.QuantityRequired;
                            break;
                        case "星期天":
                            food.Sunday = dateData.QuantityRequired;
                            break;
                    }
                }
            }
            result.FoodLists.Add(food);
        }
        return result;
    }



}
